local declMetatable;
local method;

method = {
    GetDecl = function(decl)
        if(decl.metaDecl)then return decl.metaDecl; end;
        local t = {};
        t.decl = decl;
        t.code = decl.code;
        t.id = decl.id;
        setmetatable(t, declMetatable);
        decl.metaDecl = t;
        return t;
    end,
}
method.__index = method;

declMetatable = {

    --获得函数的定义
    GetFunction = function(v)
        if(v.code=="function_decl")then
            local t = {};
            local args = {};
            local arg = v.args;
            while(true)do
                if(arg)then
                    table.insert(args,arg);
                else
                    break;
                end
                --下一个参数
                arg = arg.chain;
            end

            local retn = v.type.retn;
            t.decl = v;
            t.args = args;
            t.retn = retn;
            t.name = v.name.strg;
            return t;
        end
        return nil;
    end,
    --获得参数名
    GetParmName = function(v)
        if(v.code=="parm_decl")then
            if(v.name==nil)then return nil end;
            return v.name.strg;
        end
        return nil;
    end,
    --是否为空
    IsVoid = function(v)
        return v.code=='void_type';
    end,
    --是否是指针类型
    IsPointerType = function(v)
        if(v.code=="pointer_type")then
            return true;
        end
        return false;
    end,
    --是否是整数类型
    IsIntegerType = function(v)
        if(v.code=="integer_type")then
            return true;
        end
        return false;
    end,
    IsBoolType = function(v)
        return v.code=='boolean_type';
    end,
    IsRealType = function(v)
        return v.code=='real_type';
    end,
    IsEnumType = function(v)
        return v.code=='enumeral_type';
    end,
    --是否为结构体
    IsRecordType = function(v)
        if(v.code=="record_type")then
            return true;
        end
        return false;
    end,
    IsUnionType = function(v)
        if(v.code=='union_type')then
            return true;
        end
        return false;
    end,
    --是否是引用类型
    IsRefType = function(v)
        return v.code=='reference_type';
    end,
    --是否是结构体
    IsStruct =function(v)
        return v.code=='record_type';
    end,
    --是否是别名结构体
    IsAliasStruct = function(v)
        --cxx 
        if(v:IsStruct())then
            local vv = v.name;
            if(vv and vv.code=='type_decl')then
                if(vv.note==nil)then return true; end;
            end
        end
        return false;
    end,
    --获得别名类型的原始结构体
    GetAliasTypeBaseStruct = function(v)
        return v.unql;
    end,
    --是否为别名公用体
    IsAliasUnion = function(v)
        --cxx
        if(v.code=='union_type')then
            local vv = v.name;
            if(vv and vv.code=='type_decl')then
                if(vv.note==nil)then return true; end;
            end
        end
        return false;
    end,
    FieldExists = function(v)
        return v.flds~=nil;
    end,
    --获得类型名
    GetRecordTypeName = function(v)
        if(v:IsStruct())then
            local vv = v.name;
            if(vv and vv.code=='type_decl')then
                local name = vv.name;
                if(name.code=='identifier_node')then return name.strg; end;
                print("un name",vv.id,name.id);
                return nil;
            end
        end
    end,
    --获得union名
    GetUnionTypeName = function(v)
        if(v.code=='union_type')then
            local vv = v.name;
            if(vv and vv.code=='type_decl')then
                local name = vv.name;
                if(name.code=='identifier_node')then return name.strg; end;
                print("un name",vv.id,name.id);
                return nil;
            end
        end
    end,
    --获得类型名，包括Record,Union
    GetTypeName = function(v)
        if(v.code=='union_type')then return v:GetUnionTypeName();end;
        if(v.code=='record_type')then return v:GetRecordTypeName();end;
        if(v.code=='real_type' or v.code=='integer_type' or v.code=='void_type' or v.code=='enumeral_type')then

            if(basetype)then
                while(v.unql)do
                    v = v.unql;
                end
            end

            if(enum2int and v.code=='enumeral_type')then
                return 'int';
            end
            if(v.name==nil) then print(v.id);end;
            if(v.name.code=='type_decl')then
                return v.name.name.strg;
            end
        end
        if(v.code=='void_type')then return 'void'; end;
        if(v.code=='function_type')then
            --暂时用func类型;
            return 'func';
        end
    end,
    IsBaseType = function(v)
        if(v.code=='union_type' or v.code=='record_type'
            or v.code=='function_type')then
            return;
        end
        return true;
    end,
    IsConstType = function(v)return v.qual~=nil;end,
    IsVoidType = function(v) return v.code=='void_type'; end;
    IsArrayType = function(v)
        return v.code=='array_type';
    end,
    IsFunctionType = function(v) return v.code=='function_type';end,
    GetBaseTypeNameC = function(v)
        local code = v.code;
        if(code=='integer_type' or code=='real_type' or code=='enumeral_type')then
            return v:GetTypeName();
        end
    end,
    GetIntegerValue = function(v)
        local tsize = 8;
        if(v.type and v.type.name.strg=='bitsizetype')then
            tsize = 1;
        else
            assert(nil,'bit size?')
        end
        if(v.code=='integer_cst')then
            return tonumber(v.int)*tsize;
        end
    end,
    GetArrayTypeLenght = function(v)
        local type_size = v.elts.size:GetIntegerValue();
        local array_size = v.size:GetIntegerValue();
        return math.ceil(array_size/type_size);
    end,
    IsBitType = function(v)
        if(v.code=='integer_type' and v.name==nil and v.size)then
            return true;
        end
    end,
    GetTypeNameC = function(v,nodef)
        local ref,type = v:GetPointerRefCount();
        local s = '*********************';
        ref = s:sub(1,ref);
        if(v:IsArrayType())then
            return v.elts:GetTypeNameC(),v:GetArrayTypeLenght();
        end
        if(nodef)then
            if(type:IsBaseType())then
                --return v:GetBaseTypeNameC();
            else
                return string.format("struct %s%s",type:GetTypeName(),ref);
            end
        else
            if(type:IsAliasStruct() or type:IsBaseType())then
            else
                return string.format("struct %s%s",type:GetTypeName(),ref);
            end
        end
        return string.format("%s%s",type:GetTypeName(),ref);
    end,
    GetStructName = function(v)
        if(v:IsAliasStruct()==false)then
            return 'struct '..v:GetTypeName();
        end
    end,
    GetTypeNextFieldInfo = function(v)
        if(v.code=='record_type' or v.code=='union_type')then
            if(v.flds==nil)then return nil; end;
            return v.flds:GetTypeNextFieldInfo ();
        end
        if(v.code=='field_decl')then
            local next = v.chain;
            local name;
            if(v.name)then name = v.name.strg; end;
            local type = v.type;
            local bpos = v.bpos:GetNumberValue();
            local size = v.size:GetNumberValue();
            local algn = tonumber(v.algn);
            if(next.code~='field_decl')then next = nil end;
            return next,name,type,bpos,size,algn;
        end
        return nil;
    end,
    --解开指针类型
    UnRefType = function(v)
        if(v.code=="pointer_type")then
            return v.ptd;
        end
        return nil;
    end,
    UnPointerType = function(v)
        if(v.code=="pointer_type")then
            return v.ptd;
        end
        return nil;
    end,
    --指针的基础类型
    GetPointerBaseType = function(v)
        local ret = nil;
        while(v.code=="pointer_type")do
            ret = v.ptd;
            v = v.ptd;
        end
        return ret;
    end,
    --获得指针引用计数，比如:  int****   =4,int *** = 3
    GetPointerRefCount = function(v)
        local ret = 0;
        while(v.code=="pointer_type")do
            ret = ret + 1;
            v = v.ptd;
        end
        return ret,v;
    end,
    --获得在文件的位置
    GetFilePosition = function(v)
        local srcp = v.srcp;
        local file,line;
        if(srcp)then
            local pos = srcp:find(':');
            if(pos==nil)then
                return srcp;
            end
            file = srcp:sub(1,pos-1);
            line = tonumber(srcp:sub(pos+1))
            return file,line;
        end
        return nil;
    end,
    --获得枚举类型名
    GetEnumName = function(v)
        local name = v.name;
        if(name==nil)then return nil;end;
        while(name.code~='identifier_node')do
            if(name.code=='type_decl')then
                name = name.name;
            else
                local s = string.format('%s :%s',name.id,name.code);
                assert(0,err);
            end
        end
        return name.strg;
    end,
    --获得字段名和类型,偏移，大小
    GetRecordTypeNextFieldInfo = function(v)
        if(v.code=='record_type')then
            if(v.flds==nil)then return nil; end;
            return v.flds:GetRecordTypeNextFieldInfo();
        end
        if(v.code=='field_decl')then
            local next = v.chain;
            local name = v.name.strg;
            local type = v.type;
            local bpos = v.bpos:GetNumberValue();
            local size = v.size:GetNumberValue();
            local algn = tonumber(v.algn);
            if(next.code~='field_decl')then next = nil end;
            return next,name,type,bpos,size,algn;
        end
        return nil;
    end
    ,
    --获得枚举名和值
    GetNextEnumInfo = function(v)
        --enum.csts   .code = 'tree_list'
        if(v.code=='enumeral_type')then
            local csts = v.csts;
            if(csts)then
                return csts:GetNextEnumInfo();
            end
            return nil;
        end
        if(v.code=='tree_list')then
            local name = v.purp.strg;
            local n,value = v.valu:GetConstValue();
            local next = v.chan;
            return name,value,next;
        end
        return nil;
    end,
    --获得常量值
    GetConstValue = function(v)
        if(v:IsConstDecl())then
            --v.type = 'const_decl'
            local name = v.name.strg;
            local valu = v.cnst:GetNumberValue();
            local next = v.chain;
            if(valu==nil)then valu = v.cnst:GetNumberLow();end;
            if(next.code=='const_decl')then next = nil; end; --cxx的next(下一个常量值)是往上分析的
            return name,valu,next;
        end
        return nil;
    end,
    --获得值
    GetNumberValue = function(v)
        local n;
        if(v.code=='integer_cst')then n = v.int ; end;
        if(v.code=='real_cst')then n = v.valu; end;
        if(n)then 
            return tonumber(n);
        end
        return nil;
    end,
    --获取值
    GetNumberLow = function(v)
        local n ;
        if(v.code=='integer_cst')then n = v.low; end;
        if(v.code=='real_cst')then n = v.low; end;
        if(n)then 
            return tonumber(n);
        end
        return nil;
    end,
    --
    Is = function(v,name)
        return v.code==name;
    end,
    --
    IsConstDecl = function(v)
        return v.code=='const_decl';
    end,
    lang = function(v)
        return v.lang;
    end,
    --
    GetParmBaseType = function(v)

    end,
    --获得参数类型，名称，引用层数
    GetParmInfo = function(v)
        local name = v:GetParmName();
        local count,type = v.type:GetPointerRefCount();
        return type,name,count;
    end,
};

declMetatable.__index = function(v,name)
    local root = v.decl.root;
    local index = v.decl[name];
    if(index==nil)then
        return declMetatable[name];
    elseif(type(index)=='table')then
        return index;
    elseif(index:sub(1,1)~='@')then
        return index;
    end
    local v = root[index];
    if(v.GetDecl)then
        return v:GetDecl();
    end
    setmetatable(v,method);
    return v:GetDecl();
end;



function NewDeclMetatable()
    return method;
end



